<?php
abstract class Controller
{
    protected $_title = '';

    protected $_breadcrumbs = array();

    public static $crossParams = array();

    protected $_childControllers = array();

    protected $_loader = null;

    /**
     * @var Response
     */
    protected $_response = null;

    /**
     * @var Session
     */
    protected $_session = null;

    /**
     * @var Input
     */
    protected $_input = null;

    /**
     * Cache loaded components
     * @var array
     */
    protected $_data = array();

    public function __construct()
    {
        $this->_loader = Loader::getInstance();
        $this->_response = new Response();

        $this->_session = $this->_loader->library('session');
        $this->_input = $this->_loader->library('input');

        $this->_loader->helper('link');
    }

    ## ------------------------------------------
    ##
    ## Set common part
    ##
    public function setTitle($title)
    {
        $this->_title = $title;

        self::$crossParams['title'] = $title;
    }

    public function setBreadcrumb(array $breadcrumbs)
    {
        $this->_breadcrumbs = $breadcrumbs;
    }

    public function loadChildControllers(array $controllers)
    {
        $this->_childControllers = $controllers;
    }

    ## ------------------------------------------
    ##
    ## Hook Controller
    ##
    public function preDispatch($action)
    {
        $this->_preDispatch($action);
    }

    protected function _preDispatch($action)
    {}

    ## ------------------------------------------
    ##
    ## Response
    ##
    public function responseError($title, $description)
    {
        return $this->responseReroute('error', array(
            $title, $description
        ));
    }

    public function responseReroute($route, array $params = array())
    {
        $router = Router::create($route);
        $router->addParams($params);

        throw new OutputResponseException(FrontController::execute($router));
    }

    public function responseRedirect($redirectUrl)
    {
        $this->_response->setRedirectUrl($redirectUrl);
        $this->_response->setReturnType(Response::RETURN_REDIRECT);

        throw new OutputResponseException($this->_response);
    }

    public function responseView($templatePath, array $params = array(), $layout = '', array $layoutParams = array())
    {
        $template = new Template();

        $this->_prepareCrossParams();

        $template->style = Config::get('default_style');
        $template->templateName = $templatePath;
        $template->params = $this->_prepareParams(array_merge(self::$crossParams, $params));

        if ($layout !== '')
        {
            $template->layoutName = $layout;
            $template->layoutParams = $this->_prepareLayoutParams(array_merge(self::$crossParams, $layoutParams));
        }

        $this->_response->setContent($template->fetchContent());

        return $this->_response;
    }

    public function fetchChildController($route)
    {
        $response = FrontController::execute(Router::create($route));

        return $response->getContent();
    }

    ## ------------------------------------------
    ##
    ## Helper
    ##
    protected function _prepareParams(array $extraParams = array())
    {
        $params = $extraParams;

        $params['breadcrumbs'] = $this->_breadcrumbs;

        return $params;
    }

    protected function _prepareCrossParams()
    {
        // Scripts
        if (!isset(self::$crossParams['styles']))
        {
            self::$crossParams['styles'] = array();
        }
        if (!isset(self::$crossParams['scripts']))
        {
            self::$crossParams['scripts'] = array();
        }
    }

    protected function _prepareLayoutParams(array $extraParams = array())
    {
        $layoutParams = $extraParams;

        // Child controller
        foreach ($this->_childControllers as $paramName => $route)
        {
            $layoutParams[$paramName] = $this->fetchChildController($route);
        }

        // Base href
        $layoutParams['base_href'] = Config::get('base_href');

        // Breadcrumb
        $layoutParams['breadcrumbs'] = $this->_breadcrumbs;

        return $layoutParams;
    }
}